/********************************************************************************
*
* File: ast.c
* The abstract syntax trees for the calculator
* Programmer: Leonidas Fegaras, UTA
* Date: 12/17/97
*
********************************************************************************/

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "ast.h"


ast* mk_int ( const long x ) {
  ast* res = (ast*) malloc(sizeof(ast));
  //res->tag = int_ast;
  res->tag=ast::int_ast;
  res->info.integer = x;
  return res;
};


ast* mk_real ( const double x ) {
  ast* res = (ast*) malloc(sizeof(ast));
  res->tag = ast::real_ast;
  res->info.real = x;
  return res;
};


ast* mk_var ( const char* x ) {
  ast* res = (ast*) malloc(sizeof(ast));
  res->tag = ast::var_ast;
  res->info.variable = (char*) malloc(strlen(x)+1);
  strcpy(res->info.variable,x);
  return res;
};


ast* mk_str ( const char* x ) {
  ast* res = (ast*) malloc(sizeof(ast));
  res->tag = ast::str_ast;
  res->info.variable = (char*) malloc(strlen(x)+1);
  strcpy(res->info.variable,x);
  return res;
};


ast* mk_node ( const ast_kind tag, ast_list* args ) {
  ast* res = (ast*) malloc(sizeof(ast));
  res->tag = ast::node_ast;
  res->info.node.tag = tag;
  res->info.node.arguments = args;
  return res;
};


ast_list* cons ( ast* e, ast_list* r ) {
  ast_list* res = (ast_list*) malloc(sizeof(ast_list));
  res->elem = e;
  res->next = r;
  return res;
};

ast_list* PushBackAST(ast* e, ast_list* r)
{
    ast_list* newAstList=cons(e,NULL);
    ast_list* current=r;
    while(current->next!=NULL)
    {
        current=current->next;
    }
    current->next=newAstList;
    return r;
}

short length ( ast_list* r ) {
  short i = 0;
  for(; r != null; r=r->next) i++;
  return i;
};


ast_list* rev ( ast_list* r, ast_list* s ) {
  if (r == null)
     return s;
  return rev(r->next,cons(r->elem,s));
};


ast_list* reverse ( ast_list* r ) {
  return rev(r,null);
};


void print_ast_list ( ast_list* r,int layer ) {
  if (r == null)
     return;
  printf(" ");
  print_ast(r->elem,layer);
  print_ast_list(r->next,layer);
};

/*
void print_ast ( ast* x ) {
  switch (x->tag) {
  case ast::int_ast: printf("%d",x->info.integer); break;
  case ast::real_ast: printf("%f",x->info.real); break;
  case ast::var_ast: printf("%s",x->info.variable); break;
  case ast::str_ast: printf("\"%s\"",x->info.string); break;
  case ast::node_ast: {
      printf("(%s",ast_names[x->info.node.tag]);
      print_ast_list(x->info.node.arguments);
      printf(")");
      break;
    };
  };
};
*/
void print_ast ( ast* x ,int layer)
{
    if(layer==0)
    {
        printf("\n");
    }
    else
    {
        for(int i=0;i<layer;++i)
        {
            printf("    ");
        }
    }
    switch (x->tag)
    {
    case ast::int_ast: printf("%d\n",x->info.integer); break;
    case ast::real_ast: printf("%f\n",x->info.real); break;
    case ast::var_ast: printf("%s\n",x->info.variable); break;
    case ast::str_ast: printf("\"%s\"",x->info.string); break;
    case ast::node_ast:
    {
        printf("%s\n",ast_names[x->info.node.tag]);
        print_ast_list(x->info.node.arguments,layer+1);
        break;
    };
    };
};
